<?php
/*
 * Copyright (c) 2008 Sergey Bondari, bondari@bondari.net
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

namespace Mosaic\System;


/**
 * Resource base class.
 *
 * Generic processing resource containment class.  Event and Tile resources implement basic resource interface implementation of ifResource interface.
 * There are two important facts about this class: once it is created it stores and preserves context ID for resource processing synchronizations and
 * second it implements quite uncommon functionality which is callback stack. Callbacks stack allows node to control conveyor asynchronous event 
 * processing.
 *
 * Callback stack
 *
 * @package System
 * @subpackage Resources
 */
abstract class Resource implements ifResource,ifSerializable {
	/**
	 * Callbacks stack
	 * @var SPLStack
	 */
	private $__CALLBACKS;

	/**
	 * Identifacation of context, resource processing belongs to.
	 * @var string
	 */
	private $__CONTEXT;

	/**
	 * Constructor
	 *
	 * Reas current context identification and initializes callback stack.
	 */
	function __construct() {
		global $sys;
		$this->__CONTEXT = $sys->getContextTag();
		$this->__CALLBACKS = new \SPLStack();
	}


	/**
	 * Context tag setter 
	 * @param string Context tag
	 */
	public function setContextTag($v) {
		$this->__CONTEXT = $v;
	}

	/**
	 * Context tag getter
	 * @return string Context tag
	 */
	public function getContextTag() {
		return $this->__CONTEXT;
	}

	/**
	 * Adds a new callback into callback stack
	 * @param mixed callback
	 * @return void
	 */
	public function pushCallback($cb) {
		$this->__CALLBACKS->push($cb);
	}

	/**
	 * Returns event callback from the stack top
	 * @return mixed callback
	 */
	public function popCallback() {
		if (!$this->hasCallback()) {
			throw new RuntimeException('Resource callback stack is empty.');
		}
		return call_user_func($this->__CALLBACKS->pop(), $this);
	}
	
	/**
	 * Indicates if there are some callbacks left in stack
	 * @return boolean true if there are callbacks
	 */
	public function hasCallback() {
		return !$this->__CALLBACKS->isEmpty();
	}


	/**	
	 * Resource uniting.
	 * Used in aynchronous processing functionality when resource is delivered simultaneously to many components
	 * Must be implemented by programmer in derived classes.
	 *
	 * @param Resource Resource instance to merge with
	 * @return void
	 */
	abstract public function merge($res);


	/**	
	 * Resource serialization implementation
	 * @return string Serialzied resource data
	 */
	abstract protected function __serialize();


	/**	
	 * Resource deserialization implementation
	 * @return Resource
	 */
	abstract static protected function __deserialize($string);

	/**	
	 * Resource serialization interface.
	 * This method is used by ICC when delivering resource to other node
	 * @return string
	 */
	public final function serialize() {	
		if ($this instanceof ifTile) {
			return 'TIL:'.$this->__serialize();
		} else if ($this instanceof ifEvent) {
			return 'EVT:'.$this->__serialize();
		}
	}

	/**	
	 * Resource deserialization interface.
	 * This method is used by ICC when delivering resource to other node
	 * @return Resource
	 */
	static final public function deserialize($string) {
		if (strpos($string, 'TIL:') === 0) {
			return Tile::__deserialize(substr($string, 4));
		} else if (strpos($string, 'EVT:') === 0) {
			return Event::__deserialize(substr($string, 4));
		}
	}

}
